/**
  @(#)$Id: AL_Thread.cpp 69 2013-10-08 03:03:33Z xiaoting $
  @brief    	Thread, sometimes referred to as lightweight processes (Lightweight Process, LWP), is the smallest unit 
				of program execution flow. A standard thread by the thread ID, the current instruction poDWORDer (PC), the 
				register set and stack. In addition, the thread is an entity in the process, is system independent scheduling 
				and dispatch of the basic unit of the threads do not have the system resources, only to have a little run 
				essential resource, but it can belong to the same process other threads the shared processes have all the 
				resources. A thread can create to undo another thread, multiple threads in the same process can execute
				concurrently. Mutual restraDWORD between threads, resulting thread showing DWORDermittent running. Thread ready 
				three basic blocking and run state. Every program has at least one thread, if the program is only one thread, 
				and that is the program itself.

				A thread is a single sequential flow of control in the program. Accomplish different tasks simultaneously run 
				multiple threads in a single program, called multi-threading.

  @author		$Author: xiaoting $
  @date			$Date: 2013-10-08 11:03:33 +0800 (周二, 08 十月 2013) $
  @version		$Revision: 69 $
  @url			$URL: https://svn.code.sf.net/p/xiaoting/game/trunk/MyProject/AL_StandardLib/AL_Thread.cpp $
  @header		$Header: https://svn.code.sf.net/p/xiaoting/game/trunk/MyProject/AL_StandardLib/AL_Thread.cpp 69 2013-10-08 03:03:33Z xiaoting $
 */
#include "stdafx.h"

#ifndef CXX_AL_THREAD_H
#include "AL_Thread.h"
#endif

// AL_ErrorLog Recording
static const NCHAR g_szErrorFileInfo[] = NTEXT("$Id: AL_Thread.cpp 69 2013-10-08 03:03:33Z xiaoting $");
///////////////////////////////////////////////////////////////////////////
//			AL_Thread
///////////////////////////////////////////////////////////////////////////

/*=============================================================================*/
/*Multi-threaded programming  (LINUX / WINDOWS)                                */
#if defined(_LINUX_AL_)


/**
*ThreadFunction	1. pthread_t thread function must be a global function, in order to solve this problem
			2. Declare it as static, to prevent this file outside of the code to call this function directly.
			3. Here using a method called Virtual friend function idiom.
*
* @param VOID*
* @return VOID*
* @note
* @attention
*/
static VOID* ThreadFunction(VOID* threadObject)
{
	AL_Thread* pThread = static_cast<AL_Thread*>(threadObject);
	return pThread->Run(pThread->GetParam());
}


/**
* Construction
*
* @param
* @return
*/
AL_Thread::AL_Thread():
m_bStarted(FALSE),
m_bDetached(FALSE),
m_pParam(NULL)
{
	
}

/**
* Destruction
*
* @param
* @return
*/
AL_Thread::~AL_Thread()
{
	Stop();
}

/**
* Start
*
* @param VOID* = NULL
* @return BOOL
* @note
* @attention
*/
BOOL 
AL_Thread::Start(VOID* param)
{
	pthread_attr_t attributes;
	pthread_attr_init(&attributes);
	if (m_bDetached) {
		pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED);
	}
	m_pParam = param;
	if (pthread_create(&m_handle, &attributes, ThreadFunction, this) == 0) {
		m_bStarted = TRUE;
	}
	pthread_attr_destroy(&attribute);
}

/**
* Wait
*
* @param VOID
* @return VOID*
* @note
* @attention
*/
VOID* 
AL_Thread::Wait(VOID)
{
	// some problem
	VOID* status = NULL;
	if (m_bStarted && !m_bDetached) {
		pthread_join(handle, &status);
	}
	return status;
}

/**
* Get Vitality
*
* @param VOID
* @return VOID
* @note
* @attention
*/
VOID 
AL_Thread::Stop(VOID)
{
	if (m_Started && !m_bDetached) {
		pthread_cancel(m_handle);
		pthread_detach(m_handle);
		m_bDetached = TRUE;
	} 
}

/**
* Detach
*
* @param VOID
* @return VOID
* @note
* @attention
*/
VOID 
AL_Thread::Detach(VOID)
{
	// some problem
	if (m_Started && !m_bDetached) {
		pthread_detach(m_handle);
	}
	m_bDetached = true;
}

/**
* Sleep
*
* @param DWORD dwMilliSeconds
* @return VOID
* @note
* @attention
*/
VOID 
AL_Thread::Sleep(DWORD dwMilliSeconds)
{
	timeval timeout = { dwMilliSeconds/1000, dwMilliSeconds%1000};
	select(0, NULL, NULL, NULL, &timeout);
}

/**
* GetParam 
*
* @param VOID
* @return VOID*
* @note
* @attention
*/
VOID* 
AL_Thread::GetParam(VOID)
{
	return m_pParam;
}

#else	// _LINUX_AL_

/**
*ThreadFunction	1. HANDLE thread function must be a global function, in order to solve this problem
			2. Declare it as static, to prevent this file outside of the code to call this function directly.
			3. Here using a method called Virtual friend function idiom.
*
* @param unsigned int __stdcall
* @return VOID*
* @note
* @attention
*/
static unsigned int __stdcall ThreadFunction(VOID* threadObject)
{
	AL_Thread* pThread = static_cast<AL_Thread*>(threadObject);
	return (unsigned int)pThread->Run(pThread->GetParam());
}



/**
* Construction
*
* @param
* @return
*/
AL_Thread::AL_Thread():
m_bStarted(FALSE),
m_bDetached(FALSE),
m_pParam(NULL),
m_uiThreadID(0)
{
	
}

/**
* Destruction
*
* @param
* @return
*/
AL_Thread::~AL_Thread()
{
	Stop();
}

/**
* Start
*
* @param VOID* = NULL
* @return BOOL
* @note
* @attention
*/
BOOL 
AL_Thread::Start(VOID* param)
{
	if (!m_bStarted) {
		m_pParam = param;
		if (m_threadHandle = (HANDLE)_beginthreadex(NULL, 0, ThreadFunction, this, 0, &m_uiThreadID)) {
			if (m_bDetached) {
				CloseHandle(m_threadHandle);
			}
			m_bStarted = TRUE;
		}
	}
	return m_bStarted;
}

/**
* Wait
*
* @param VOID
* @return VOID*
* @note
* @attention
*/
VOID* 
AL_Thread::Wait(VOID)
{
	// some problem
	DWORD status = (DWORD) NULL;
	if (m_bStarted && !m_bDetached) {
		WaitForSingleObject(m_threadHandle, INFINITE);
		GetExitCodeThread(m_threadHandle, &status);       
		CloseHandle(m_threadHandle);
		m_bDetached = true;
	}
	return (VOID*)status;
}

/**
* Get Vitality
*
* @param VOID
* @return VOID
* @note
* @attention
*/
VOID 
AL_Thread::Stop(VOID)
{
	if (m_bStarted && !m_bDetached) {
		TerminateThread(m_threadHandle, 0);
		//Closing a thread handle does not terminate 
		//the associated thread. 
		//To remove a thread object, you must terminate the thread, 
		//then close all handles to the thread.
		//The thread object remains in the system until 
		//the thread has terminated and all handles to it have been 
		//closed through a call to CloseHandle
		CloseHandle(m_threadHandle);
		m_bDetached = true;
	}
}

/**
* Detach
*
* @param VOID
* @return VOID
* @note
* @attention
*/
VOID 
AL_Thread::Detach(VOID)
{
	// some problem
	if (m_bStarted && !m_bDetached) {
		CloseHandle(m_threadHandle);
	}
	m_bDetached = TRUE;
}

/**
* Sleep
*
* @param DWORD dwMilliSeconds
* @return VOID
* @note
* @attention
*/
VOID 
AL_Thread::Sleep(DWORD dwMilliSeconds)
{
	::Sleep(dwMilliSeconds);
}

/**
* GetParam 
*
* @param VOID
* @return VOID*
* @note
* @attention
*/
VOID* 
AL_Thread::GetParam(VOID)
{
	return m_pParam;
}

#endif	// _WINDOWS_AL_

/* EOF */